package com.cdk8s.example.simplespringboot.service;


import com.cdk8s.example.simplespringboot.properties.TencentCosParamProperties;
import com.cdk8s.example.simplespringboot.properties.UploadParamProperties;
import com.cdk8s.example.simplespringboot.utils.DatetimeUtil;
import com.cdk8s.example.simplespringboot.utils.ExceptionUtil;
import com.cdk8s.example.simplespringboot.utils.FileUtil;
import com.cdk8s.example.simplespringboot.utils.StringUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.StorageClass;
import com.qcloud.cos.region.Region;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * 官网文档：
 * https://cloud.tencent.com/document/product/436/10199
 */
@Slf4j
@Service
public class TencentCosService {

	@Autowired
	private TencentCosParamProperties tencentCosParamProperties;

	@Autowired
	private UploadParamProperties uploadParamProperties;

	// region=====================================查询业务 start=====================================

	public String getOriginalFileName(MultipartFile file) {
		if (null == file) {
			throw new RuntimeException("上传文件不能为空");
		}

		String originalFilename = file.getOriginalFilename();
		if (StringUtil.isBlank(originalFilename)) {
			throw new RuntimeException("上传文件名不能为空");
		}

		return FileUtil.handleFileName(originalFilename);
	}

	public String getFileRelativePath(String uuidFileName) {
		return "/" + DatetimeUtil.formatDate(new Date(), "yyyy-MM/dd") + "/" + uuidFileName;
	}

	public String getFileFullUrl(String fileRelativePath, Boolean enableCdn) {
		if (enableCdn) {
			return tencentCosParamProperties.getFileCdnDomain() + fileRelativePath;
		}

		return tencentCosParamProperties.getFileSourceDomain() + fileRelativePath;
	}

	// endregion=====================================查询业务 end=====================================

	// region=====================================操作业务 start=====================================

	/**
	 * 参考官网 demo
	 * https://github.com/tencentyun/cos-java-sdk-v5/blob/master/src/main/java/com/qcloud/cos/demo/SimpleUploadFileDemo.java
	 */
	public void simpleUploadFileFromStream(MultipartFile file, String cosFileRelativePath) {
		//路径前面需要/
		if (!cosFileRelativePath.startsWith("/")) {
			cosFileRelativePath = "/" + cosFileRelativePath;
		}

		String bucketName = tencentCosParamProperties.getBucketName();
		COSClient cosClient = getCosClient();

		try {
			InputStream inputStream = file.getInputStream();

			ObjectMetadata objectMetadata = new ObjectMetadata();
			// 从输入流上传必须制定content length, 否则http客户端可能会缓存所有数据，存在内存OOM的情况
			objectMetadata.setContentLength(file.getSize());

			// 默认下载时根据cos路径key的后缀返回响应的contenttype, 上传时设置contenttype会覆盖默认值
			objectMetadata.setContentType(file.getContentType());

			PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, cosFileRelativePath, inputStream, objectMetadata);

			// 设置存储类型, 默认是标准(Standard), 低频(standard_ia)
			putObjectRequest.setStorageClass(StorageClass.Standard);
			PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);

			// putobjectResult会返回文件的etag
			String etag = putObjectResult.getETag();
		} catch (Exception e) {
			ExceptionUtil.printStackTraceAsString(e);
			throw new RuntimeException("cos 文件上传失败");
		} finally {
			// 关闭客户端
			cosClient.shutdown();
		}
	}


	/**
	 * 默认的 cos 路径
	 *
	 * @param fileFullPath
	 * @return
	 */
	public String uploadIconFromLocal(String fileFullPath) {
		String realFileName = FileUtil.getRealFileName(fileFullPath);
		String cosFileRelativePath = getFileRelativePath(realFileName);
		cosFileRelativePath = "/icon" + cosFileRelativePath;

		simpleUploadFileFromLocal(new File(fileFullPath), cosFileRelativePath);
		FileUtil.deleteFile(fileFullPath);
		return cosFileRelativePath;
	}

	/**
	 * 自己指定的 cos 路径
	 *
	 * @param fileFullPath
	 * @param cosPath
	 * @return
	 */
	public String uploadIconFromLocal(String fileFullPath, String cosPath) {
		String realFileName = FileUtil.getRealFileName(fileFullPath);
		String cosFileRelativePath = cosPath + "/" + realFileName;
		simpleUploadFileFromLocal(new File(fileFullPath), cosFileRelativePath);
		FileUtil.deleteFile(fileFullPath);
		return cosFileRelativePath;
	}

	/**
	 * 通过 url 上传文件
	 * @param iconUrl
	 * @param byteByFileHttpUrl 把这个变量提取到外部是因为 DownloadUtil 方法里面日志打印 EventTrackingUtil.log(fileHttpUrl, "GetIconException"); 涉及到 MDC
	 * @return
	 */
	public String uploadIconFromIconUrl(String iconUrl, byte[] byteByFileHttpUrl) {
		if (null == byteByFileHttpUrl) {
			// 没抓取到
			return null;
		}

		// 提取后缀
		String fileSuffix = getIconFileSuffix(iconUrl);

		// 上传
		return uploadIcon(byteByFileHttpUrl, fileSuffix);
	}

	public String getIconFileSuffix(String iconUrl) {
		// 获取文件后缀
		List<String> suffixList = new ArrayList<>();
		suffixList.add(".ico");
		suffixList.add(".png");
		suffixList.add(".jpg");
		suffixList.add(".jpeg");
		suffixList.add(".svg");
		suffixList.add(".gif");
		suffixList.add(".bmp");

		// 提取后缀
		boolean flag = StringUtil.endsWithAnyIgnoreCase(iconUrl, suffixList);
		String fileSuffix;
		if (flag) {
			fileSuffix = FileUtil.getFileExtension(iconUrl);
		} else {
			// 如果没有任何匹配就直接按照 ico 后缀处理了
			fileSuffix = "ico";
		}

		return fileSuffix;
	}

	public String uploadIcon(byte[] byteByFileHttpUrl, String fileSuffix) {
		String uuidFileName = FileUtil.getNewFileNameByUUID() + "." + fileSuffix;

		String fileFullPath = uploadParamProperties.getLocalUploadStoragePath() + File.separator + uuidFileName;
		FileUtil.writeFileToDisk(byteByFileHttpUrl, fileFullPath);

		String cosFileRelativePath = getFileRelativePath(uuidFileName);
		cosFileRelativePath = "/icon" + cosFileRelativePath;

		simpleUploadFileFromLocal(new File(fileFullPath), cosFileRelativePath);
		FileUtil.deleteFile(fileFullPath);
		return cosFileRelativePath;
	}


	/**
	 * 本地文件上传核心
	 */
	public void simpleUploadFileFromLocal(File localFile, String cosFileRelativePath) {
		String bucketName = tencentCosParamProperties.getBucketName();
		COSClient cosClient = getCosClient();

		try {
			PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, cosFileRelativePath, localFile);

			// 设置存储类型, 默认是标准(Standard), 低频(standard_ia)
			putObjectRequest.setStorageClass(StorageClass.Standard);
			PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);

			// putobjectResult会返回文件的etag
			String etag = putObjectResult.getETag();
		} catch (Exception e) {
			ExceptionUtil.printStackTraceAsString(e);
			throw new RuntimeException("cos 文件上传失败");
		} finally {
			// 关闭客户端
			cosClient.shutdown();
		}
	}

	// endregion=====================================操作业务 end=====================================

	// region=====================================私有方法 start=====================================


	private COSClient getCosClient() {
		COSCredentials cred = new BasicCOSCredentials(tencentCosParamProperties.getSecretId(), tencentCosParamProperties.getSecretKey());
		ClientConfig clientConfig = new ClientConfig(new Region(tencentCosParamProperties.getRegion()));
		return new COSClient(cred, clientConfig);
	}

	// endregion=====================================私有方法 end=====================================

}
